Keep scroll history
authorMatthias Clasen <mclasen@redhat.com>
Tue, 9 Jun 2020 00:29:38 +0000 (20:29 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Tue, 9 Jun 2020 17:43:03 +0000 (13:43 -0400)
Similar to how we keep motion history for compressed
events, keep scroll history for compressed scroll
events.

gdk/gdkevents.c
gdk/gdkevents.h
gdk/gdkeventsprivate.h

index 1b20a57dac41e9847e09d1d4539fa6b105752ec3..7c621f7e5b2ee68e5b9bc77c8d689df7b4358177 100644 (file)
@@ -632,9 +632,7 @@ gdk_event_queue_handle_scroll_compression (GdkDisplay *display)
   GdkEvent *last_event = NULL;
   GList *scrolls = NULL;
   double delta_x, delta_y;
-  double dx, dy;
-
-  delta_x = delta_y = 0;
+  GArray *history = NULL;
 
   l = g_queue_peek_tail_link (&display->queued_events);
 
@@ -664,18 +662,31 @@ gdk_event_queue_handle_scroll_compression (GdkDisplay *display)
       device = event->device;
       scrolls = l;
 
-      gdk_scroll_event_get_deltas (event, &dx, &dy);
-      delta_x += dx;
-      delta_y += dy;
-
       l = l->prev;
     }
 
+  delta_x = delta_y = 0;
+
   while (scrolls && scrolls->next != NULL)
     {
+      GdkEvent *event = scrolls->data;
       GList *next = scrolls->next;
+      GdkScrollHistory h;
+      double dx, dy;
+
+      if (!history)
+        history = g_array_new (FALSE, TRUE, sizeof (GdkScrollHistory));
+
+      gdk_scroll_event_get_deltas (event, &dx, &dy);
+      delta_x += dx;
+      delta_y += dy;
 
-      gdk_event_unref (scrolls->data);
+      h.time = gdk_event_get_time (event);
+      h.delta_x = dx;
+      h.delta_y = dy;
+      g_array_append_val (history, h);
+
+      gdk_event_unref (event);
       g_queue_delete_link (&display->queued_events, scrolls);
       scrolls = next;
     }
@@ -683,19 +694,23 @@ gdk_event_queue_handle_scroll_compression (GdkDisplay *display)
   if (scrolls)
     {
       GdkEvent *old_event, *event;
+      double dx, dy;
 
       old_event = scrolls->data;
 
+      gdk_scroll_event_get_deltas (old_event, &dx, &dy);
       event = gdk_scroll_event_new (surface,
                                     device,
                                     gdk_event_get_source_device (old_event),
                                     gdk_event_get_device_tool (old_event),
                                     gdk_event_get_time (old_event),
                                     gdk_event_get_modifier_state (old_event),
-                                    delta_x,
-                                    delta_y,
+                                    delta_x + dx,
+                                    delta_y + dy,
                                     gdk_scroll_event_is_stop (old_event));
 
+      ((GdkScrollEvent *)event)->history = history;
+
       g_queue_delete_link (&display->queued_events, scrolls);
       g_queue_push_tail (&display->queued_events, event);
     }
@@ -2247,6 +2262,8 @@ gdk_scroll_event_finalize (GdkEvent *event)
   GdkScrollEvent *self = (GdkScrollEvent *) event;
 
   g_clear_object (&self->tool);
+  if (self->history)
+    g_array_free (self->history, TRUE);
 
   GDK_EVENT_SUPER (self)->finalize (event);
 }
@@ -2394,6 +2411,44 @@ gdk_scroll_event_is_stop (GdkEvent *event)
   return self->is_stop;
 }
 
+/**
+ * gdk_scroll_event_get_history:
+ * @event: (type GdkScrollEvent): a scroll #GdkEvent
+ * @out_n: (out): Return location for the length of the returned array
+ *
+ * Retrieves the history of the @event, as a list of times and deltas.
+ *
+ * Returns: (transfer container) (array length=out_n) (nullable): an
+ *   array of #GdkScrollHistory
+ */
+GdkScrollHistory *
+gdk_scroll_event_get_history (GdkEvent *event,
+                              guint    *out_n)
+{
+  GdkScrollEvent *self = (GdkScrollEvent *) event;
+
+  g_return_val_if_fail (GDK_IS_EVENT (event), NULL);
+  g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_SCROLL), NULL);
+  g_return_val_if_fail (out_n != NULL, NULL);
+
+  if (self->history &&
+      self->history->len > 0)
+    {
+      GdkScrollHistory *result;
+
+      *out_n = self->history->len;
+
+      result = g_new (GdkScrollHistory, self->history->len);
+      memcpy (result, self->history->data, sizeof (GdkScrollHistory) * self->history->len);
+
+      return result;
+    }
+
+  *out_n = 0;
+
+  return NULL;
+}
+
 /* }}} */
 
 /* {{{ GdkTouchpadEvent */
index e7027175419398d0bf448cb3fcd85874608af710..17f76ce0d8777169e881853b9bd62c2e32e8799c 100644 (file)
@@ -392,6 +392,17 @@ GDK_AVAILABLE_IN_ALL
 void                    gdk_scroll_event_get_deltas     (GdkEvent *event,
                                                          double   *delta_x,
                                                          double   *delta_y);
+
+typedef struct {
+  guint32 time;
+  double delta_x;
+  double delta_y;
+} GdkScrollHistory;
+
+GDK_AVAILABLE_IN_ALL
+GdkScrollHistory *      gdk_scroll_event_get_history    (GdkEvent *event,
+                                                         guint    *out_n);
+
 GDK_AVAILABLE_IN_ALL
 gboolean                gdk_scroll_event_is_stop        (GdkEvent *event);
 GDK_AVAILABLE_IN_ALL
index 0fd0b3e908a73c2271638721bb4fbfd892f256d0..a21e4587463457436f8dcd1d02d15e212c0b9f2d 100644 (file)
@@ -211,6 +211,9 @@ struct _GdkTouchEvent
  * @pointer_emulated: whether the scroll event was the result of
  *   a pointer emulation
  * @tool: a #GdkDeviceTool
+ * @history: (element-type GdkScrollHistory): array of times and deltas
+ *   for other scroll events that were compressed before delivering the
+ *   current event
  *
  * Generated from button presses for the buttons 4 to 7. Wheel mice are
  * usually configured to generate button press events for buttons 4 and 5
@@ -232,6 +235,7 @@ struct _GdkScrollEvent
   gboolean pointer_emulated;
   gboolean is_stop;
   GdkDeviceTool *tool;
+  GArray *history; /* <GdkScrollHistory> */
 };
 
 /*